package com.syf.kit.core.dao.impl;

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.syf.core.config.SyApplicationConfiguration;
import com.syf.kit.AppPropertiesUtils;
import com.syf.kit.core.dao.SyfRdsDaoUtilFactory;
import com.syf.kit.core.dao.log.SelfDefineMybatisLog;
import com.syf.kit.core.dao.mapper.MapperType;
import com.syf.kit.core.dao.mapper.SyfMapper;
import com.syf.kit.core.dao.mapper.registry.SyfAbstractDtoMapperRegistry;
import com.syf.kit.core.dao.mapper.registry.SyfMPDtoMapperRegistry;
import com.syf.kit.core.ds.impl.SyfDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import javax.sql.DataSource;

/**
 * 单个类型的数据源对应的DaoUtil的工厂类
 */
public abstract class SingleRdsDaoUtilsFactory implements SyfRdsDaoUtilFactory {
    private final SyfDataSource syfDataSource;

    /***
     * mybatis 事务工厂
     * */
    private final TransactionFactory dbTxFactory;

    /**
     * dao mapper管理器，它主要过程为：通过扫描带@Table注解的BaseDTO的集合，然后通过byteBuddy自动生成对应的mapper
     */
    private SyfAbstractDtoMapperRegistry mapperRegistry;

    private SqlSessionFactory sqlSessionFactory;

    private final boolean autoCommit;

    private final MapperType mapperType;

    public SingleRdsDaoUtilsFactory(SyfDataSource syfDataSource, boolean autoCommit, MapperType mapperType) {
        this(syfDataSource, new JdbcTransactionFactory(), autoCommit, mapperType);
    }

    public SingleRdsDaoUtilsFactory(SyfDataSource syfDataSource, TransactionFactory dbTxFactory, boolean autoCommit, MapperType mapperType) {
        this.syfDataSource = syfDataSource;
        this.dbTxFactory = dbTxFactory;
        this.autoCommit = autoCommit;
        this.mapperType = mapperType;
        initialize(SyApplicationConfiguration.getAppBasePackage());
    }

    /**
     * 初始化
     */
    private void initialize(String baseScanPackage) {

        if (MapperType.MYBATIS_PLUS.equals(mapperType)) {
            // 1、创建mapper注册器
            this.mapperRegistry = new SyfMPDtoMapperRegistry(baseScanPackage);

            // 2、创建 MybatisConfiguration
            MybatisConfiguration configuration = getMPConfiguration();

            // 3、将BaseDTO mapper注册到对应mapper框架中（TK或者MP）
            mapperRegistry.registerMapper(null, configuration);

            // 4、构建mybatis-plus需要的Global Config，将mapper注入mybatis（自动生成实现baseMapper的基础方法映射）
            enhanceMybatisByMP(configuration);

            // 4、创建sqlSessionFactory
            Environment environment = new Environment("mybatis-plus", new JdbcTransactionFactory(), covertDbDataSource(syfDataSource));
            configuration.setEnvironment(environment);
            MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
            mybatisSqlSessionFactoryBean.setConfiguration(configuration);
            mybatisSqlSessionFactoryBean.setDataSource(covertDbDataSource(syfDataSource));
            try {
                this.sqlSessionFactory = mybatisSqlSessionFactoryBean.getObject();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }

//        else if (MapperType.MYBATIS_PLUS.equals(mapperType)) {
//            // 1、创建mapper注册器
//            this.mapperRegistry = new SyfTKDtoMapperRegistry(SyfApplicationConfiguration.getAppBasePackage());
//            // 2、加载mybatis，完成SqlSessionFactory初始化
//            this.sqlSessionFactory = buildSqlSessionFactory(RdsDSCont.DEFAULT_DS_NAME);
//
//            // 3、初始化tk.mybatis.mapper的MapperHelper
//            MapperHelper mapperHelper = buildTkMapperHelper();
//
//            // 4、将BaseDTO mapper注册到对应mapper框架中（TK或者MP）
//            mapperRegistry.registerMapper(sqlSessionFactory, mapperHelper);
//        }

        else {
            throw new RuntimeException("目前暂只支持MP(MybatisPlus)框架!");
        }
    }

    private void enhanceMybatisByMP(MybatisConfiguration configuration) {
        //构建mybatis-plus需要的Global Config
        GlobalConfig globalConfig = new GlobalConfig();
        //此参数会自动生成实现baseMapper的基础方法映射
        globalConfig.setSqlInjector(new DefaultSqlInjector());
        //设置id生成器
        globalConfig.setIdentifierGenerator(new DefaultIdentifierGenerator(AppPropertiesUtils.getMacheId(), AppPropertiesUtils.getIdcId()));
        //设置超类mapper
        globalConfig.setSuperMapperClass(SyfMapper.class);
        //给configuration注入GlobalConfig里面的配置
        GlobalConfigUtils.setGlobalConfig(configuration, globalConfig);
    }

    /**
     * 创建MybatisPlus的MybatisConfiguration
     */
    public MybatisConfiguration getMPConfiguration() {
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setUseGeneratedKeys(true);
        configuration.setLogImpl(SelfDefineMybatisLog.class);

        return configuration;
    }

//    /**
//     * 创建SqlSessionFactory
//     */
//    private SqlSessionFactory buildSqlSessionFactory(String dsName) {
//        Configuration configuration = new Configuration();
//        Environment environment = new Environment(dsName, this.dbTxFactory, covertDbDataSource(syfDataSource));
//        configuration.setEnvironment(environment);
//        configuration.setLogImpl(SelfDefineMybatisLog.class);
//        configuration.setMapUnderscoreToCamelCase(true);
//        PageInterceptor pageInterceptor = new PageInterceptor();
//        configuration.addInterceptor(pageInterceptor);
//        return new SqlSessionFactoryBuilder().build(configuration);
//    }
//
//    /**
//     * 创建通用mapper的MapperHelper
//     */
//    private MapperHelper buildTkMapperHelper() {
//        MapperHelper mapperHelper = new MapperHelper();
//        //特殊配置
//        Config config = new Config();
//        //主键自增回写方法,默认值MYSQL,详细说明请看文档
//        config.setIDENTITY("MYSQL");
//        //支持getter和setter方法上的注解
//        config.setEnableMethodAnnotation(true);
//        // 空字符串不代表空？
//        config.setNotEmpty(true);
//        //校验Example中的类型和最终调用时Mapper的泛型是否一致
//        config.setCheckExampleEntityClass(true);
//        //启用简单类型
//        config.setUseSimpleType(true);
//        //枚举按简单类型处理
//        config.setEnumAsSimpleType(true);
//        //自动处理关键字 - mysql
//        config.setWrapKeyword("`{0}`");
//        //设置配置
//        mapperHelper.setConfig(config);
//        return mapperHelper;
//    }


    public SyfAbstractDtoMapperRegistry getMapperRegistry() {
        return mapperRegistry;
    }

    public SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }

    /**
     * 根据SyfDataSource转换获得db原始的DataSource
     */
    public abstract DataSource covertDbDataSource(SyfDataSource syfDataSource);

    public boolean isAutoCommit() {
        return autoCommit;
    }

    public MapperType getMapperType() {
        return mapperType;
    }
}
